/*
 * Copyright (C) 2008 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.esm.sm800.util;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.ImageFormat;
import android.graphics.Paint;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Size;
import android.view.Surface;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;

import com.esm.sm800.database.manager.SystemCenter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;


public final class Camera2Manager {

    private static final String TAG = Camera2Manager.class.getSimpleName();

    private static Camera2Manager cameraManager;

    private final Context context;

    public static void init(Context context) {
        if (cameraManager == null) {
            cameraManager = new Camera2Manager(context);
        }
    }

    public static Camera2Manager get() {
        return cameraManager;
    }

    private Camera2Manager(Context context) {
        this.context = context;
    }

    public Context getContext() {
        return context;
    }

    //----
    private static final int REQUEST_CAMERA_PERMISSION = 1;

    private CameraDevice cameraDevice = null;
    private CameraCaptureSession cameraCaptureSessions;
    private CaptureRequest.Builder captureRequestBuilder;
    private Size imageDimension;
    private ImageReader imageReader;
    private static final int IMAGE_FORMAT = ImageFormat.JPEG;
    private static final int MAX_PREVIEW_WIDTH = 1920;
    private static final int MAX_PREVIEW_HEIGHT = 1080;

    private Handler backgroundHandler;
    private HandlerThread backgroundThread;

    public ImageView _imageView = null;

    int _imagw = 0;
    int _imagh = 0;

    private void openCamera() {
        CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
        try {
            String[] cameraIdList = manager.getCameraIdList();
            int index = 0;
            if (cameraIdList.length > 1) {
                index = 1;
            }
            String cameraId = manager.getCameraIdList()[index];
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
            StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            assert map != null;
            imageDimension = map.getOutputSizes(ImageFormat.JPEG)[0];

            _imagw = imageDimension.getWidth();
            _imagh = imageDimension.getHeight();
            // For still image captures, we use the largest available size.
            imageReader = ImageReader.newInstance(_imagw, _imagh, IMAGE_FORMAT, 2);
            List<Surface> outputSurfaces = Arrays.asList(imageReader.getSurface());

            _needlelen = -9;//

            CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
                @Override
                public void onOpened(@NonNull CameraDevice camera) {
                    cameraDevice = camera;
                    createCameraPreviewSession();
                }

                @Override
                public void onDisconnected(@NonNull CameraDevice camera) {
                    cameraDevice.close();
                }

                @Override
                public void onError(@NonNull CameraDevice camera, int error) {
                    if (cameraDevice != null) {
                        cameraDevice.close();
                        cameraDevice = null;
                    }
                }
            };

            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                // TODO: Consider calling
                //    ActivityCompat#requestPermissions
                // here to request the missing permissions, and then overriding
                //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                //                                          int[] grantResults)
                // to handle the case where the user grants the permission. See the documentation
                // for ActivityCompat#requestPermissions for more details.
                return;
            }
            manager.openCamera(cameraId, stateCallback, backgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    //再次拍照时调用
    public void rePz() {
        if (SystemCenter.getInstance().hzBitmap != null && !SystemCenter.getInstance().hzBitmap.isRecycled()) {
            SystemCenter.getInstance().hzBitmap.recycle();
            SystemCenter.getInstance().hzBitmap = null;
        }
        if (cameraDevice == null) {
            openCamera();
        } else {
           createCameraPreviewSession(); //还针时拍照
        }
    }

    public int getNeedelen() {
        _needlelen = calculateLength();
        return _needlelen;//识别成功后>=0 -- 最长识别时间 < 5秒
    }

    int _needlelen = -1000;
    private int calculateLength() {
        if (SystemCenter.getInstance().hzBitmap == null) {
            return -1;
        }
        //x [25, 290] 列坐标  y [30, 60] 行坐标 -- 在这个区域范围计算长度
        int len = 0;
        int w = SystemCenter.getInstance().hzBitmap.getWidth();
        int h = SystemCenter.getInstance().hzBitmap.getHeight();

        for (int x = 25; x < w && x < 290; x++) {
            for (int y = 30; y < h && y < 60; y++) {
                int pixelColor = SystemCenter.getInstance().hzBitmap.getPixel(x, y);
                int red = Color.red(pixelColor);
                int green = Color.green(pixelColor);
                int blue = Color.blue(pixelColor);
                if (red > 240 && green > 240 && blue > 240) {//250针白色，其他为灰色
                    len++;
                    break;
                }
            }
        }
        return len;
    }

    private void createCameraPreviewSession() {

        try {
            SurfaceTexture texture = new SurfaceTexture(66);
            texture.setDefaultBufferSize(_imagw, _imagh);
            Surface surface = new Surface(texture);

            // Create a capture request builder and set the output surface.
            captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            captureRequestBuilder.addTarget(surface);

            // Create a camera capture session with the preview and still image outputs.
            cameraDevice.createCaptureSession(Arrays.asList(surface, imageReader.getSurface()), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    if (cameraDevice == null) {
                        return;
                    }

                    // Start the camera preview.
                    cameraCaptureSessions = session;
                    updatePreview();

                    // Trigger an automatic capture.
                    triggerImageCapture();
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                }
            }, backgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void updatePreview() {
        if (cameraDevice == null) {
            return;
        }

        try {
            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);

            CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                    super.onCaptureCompleted(session, request, result);
                }
            };

            cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), captureCallback, backgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void triggerImageCapture() {
        try {
            final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            captureBuilder.addTarget(imageReader.getSurface());

            // Use the same AE and AF modes as the preview.
            captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);

            CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                    super.onCaptureCompleted(session, request, result);

                    // Get the image from the ImageReader.
                    Image image = imageReader.acquireLatestImage();
                    if (image != null) {
                        saveImage(image);
                        image.close();
                    }
                }
            };

            cameraCaptureSessions.capture(captureBuilder.build(), captureCallback, backgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void saveImage(Image image) {
        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
        byte[] bytes = new byte[buffer.remaining()];
        buffer.get(bytes);

        if (SystemCenter.getInstance().hzBitmap != null && !SystemCenter.getInstance().hzBitmap.isRecycled()) {
            SystemCenter.getInstance().hzBitmap.recycle();
            SystemCenter.getInstance().hzBitmap = null;
        }

        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        if (bitmap == null) {
            // 解码失败，处理错误情况
            // ...
        } else {
            //1920x1080
            //取中间320x90-> 640x180
            int w = bitmap.getWidth();
            int h = bitmap.getHeight();
            //左上角（0，0）
            Bitmap croppedBitmap = Bitmap.createBitmap(bitmap, w/2-320, h/2-90, 640, 180);
            SystemCenter.getInstance().hzBitmap = convertToGrayscale(croppedBitmap);

            if (_imageView != null) {
                _imageView.setImageBitmap(SystemCenter.getInstance().hzBitmap);
            }
            saveBitmapToFile(SystemCenter.getInstance().hzBitmap);

            if (croppedBitmap != null && !croppedBitmap.isRecycled()) {
                croppedBitmap.recycle();
                croppedBitmap = null;
            }
        }

        if (bitmap != null && !bitmap.isRecycled()) {
            bitmap.recycle();
            bitmap = null;
        }

    }

    public Bitmap convertToGrayscale(Bitmap originalBitmap) {
        if (originalBitmap == null) {
            return null;
        }

        int width = originalBitmap.getWidth();
        int height = originalBitmap.getHeight();

        // 创建一个与原始Bitmap相同大小的Bitmap
        Bitmap grayscaleBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

        // 创建一个Canvas，用于在新Bitmap上绘图
        Canvas canvas = new Canvas(grayscaleBitmap);
        Paint paint = new Paint();
        ColorMatrix colorMatrix = new ColorMatrix();

        // 设置ColorMatrix为灰度效果
        //colorMatrix.setSaturation(0);
        // 设置ColorMatrix为灰度效果
        float[] matrix = new float[]{
                0.3f, 0.59f, 0.11f, 0, 0,
                0.3f, 0.59f, 0.11f, 0, 0,
                0.3f, 0.59f, 0.11f, 0, 0,
                0, 0, 0, 1, 0
        };
        colorMatrix.set(matrix);

        // 创建一个ColorMatrixColorFilter，并将其应用于Paint对象
        ColorMatrixColorFilter colorMatrixFilter = new ColorMatrixColorFilter(colorMatrix);
        paint.setColorFilter(colorMatrixFilter);

        // 使用Paint对象在Canvas上绘制原始Bitmap
        canvas.drawBitmap(originalBitmap, 0, 0, paint);

        return grayscaleBitmap;
    }


    //Utils.deleteDir(path); -- 定时清空图片
    public void saveBitmapToFile(Bitmap bitmap) {

        if (bitmap == null) {
            return;
        }

        String path = getFilesPath(context) + "/ESMJPG/";
        File dir = new File(path);
        boolean isok = false;
        if (!dir.exists()) {
            isok = dir.mkdirs();
        }

        //增加月的文件夹--清除3个月前的图片
        String mmdir = new SimpleDateFormat("yyyyMM").format(new Date());
        path = path + mmdir + "/";
        File dir1 = new File(path);
        isok = false;
        if (!dir1.exists()) {
            isok = dir1.mkdirs();
        }

        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        //调整保存图片的大小 1920x1080 -> 240x135
        Bitmap selectImage = Utils.scaleBitmap(bitmap, w / 8, h / 8);

        //保存图片
        String timeStamp = new SimpleDateFormat("yyMMdd_HHmmss").format(new Date());
        String imageFileName = timeStamp + ".jpg";
        String hzJpgpath = path + imageFileName;
        SystemCenter.getInstance().hzJpgpath = hzJpgpath;

        File outputFile = new File(path, imageFileName);
        try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
            // 压缩Bitmap到指定输出流中
            // 第一个参数是压缩格式（Bitmap.CompressFormat），这里使用JPEG
            // 第二个参数是压缩质量，范围是0（最低质量，文件最小）到100（最高质量，文件最大）
            selectImage.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
            // 确保数据写入输出流
            outputStream.flush();
            // 成功保存后可以在这里做一些操作，比如通知用户或更新UI
        } catch (IOException e) {
            e.printStackTrace();
            // 处理异常，比如显示错误消息或记录日志
        }

        if (selectImage != null && !selectImage.isRecycled()) {
            selectImage.recycle();
            selectImage = null;
        }
    }

    public String getFilesPath(Context context) {
        String filePath;
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
                || !Environment.isExternalStorageRemovable()) {
//外部存储可用
            filePath = context.getExternalFilesDir(null).getPath();
        } else {
//外部存储不可用
            filePath = context.getFilesDir().getPath();
        }
        return filePath;
    }

}
/*
自动拍照保存文件，并使用bimap
1. TextureView 的 layout_width设为1dp 不影响生成的图片
2. 手动调用 createCameraPreviewSession(); 会重新生成图片 (初始化的时候存了1张照片)
3. pad摄像头800w像素，3264x2448
   改变存图的尺寸为 352x288   -- 54KB

**             imageReader = ImageReader.newInstance(_imagw, _imagh, IMAGE_FORMAT, 2); --不乱改尺寸就cameraDevice就不会出错关闭
SystemCenter.getInstance().hzBitmap -- 保存原始的位图
图片文件保存缩小尺寸
 */
